/* mbed Microcontroller Library
 * (C)Copyright TOSHIBA ELECTRONIC DEVICES & STORAGE CORPORATION 2018 All rights reserved
 * SPDX-License-Identifier: Apache-2.0
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "mbed_assert.h"
#include "pinmap.h"
#include "gpio_include.h"

void pin_function(PinName pin, int function)
{
    int port     = 0;
    uint8_t bit  = 0;
    uint8_t func = 0;
    uint8_t dir  = 0;
    uint32_t port_base = 0;
    uint32_t mode_base = 0;

    /* Assert that pin is valid*/
    MBED_ASSERT(pin != NC);

    /* Calculate pin function and pin direction*/
    func = PIN_FUNC(function);
    dir  = PIN_DIR(function);

    /* Calculate port and pin position*/
    port = PIN_PORT(pin);
    bit  = PIN_POS(pin);

    port_base = BITBAND_PORT_BASE(port);
    /* Initialization PxFR OFF */
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR1);
    BITBAND_PORT_CLR(mode_base, bit);
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR2);
    BITBAND_PORT_CLR(mode_base, bit);
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR3);
    BITBAND_PORT_CLR(mode_base, bit);
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR4);
    BITBAND_PORT_CLR(mode_base, bit);
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR5);
    BITBAND_PORT_CLR(mode_base, bit);
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR6);
    BITBAND_PORT_CLR(mode_base, bit);
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR7);
    BITBAND_PORT_CLR(mode_base, bit);

    /* Initialize Input */
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_CR);
    BITBAND_PORT_CLR(mode_base, bit);
    mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_IE);
    BITBAND_PORT_SET(mode_base, bit);
    switch (func) {
        case 0:
            break;
        case 1:
            mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR1);
            break;
        case 2:
            mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR2);
            break;
        case 3:
            mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR3);
            break;
        case 4:
            mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR4);
            break;
        case 5:
            mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR5);
            break;
        case 6:
            mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR6);
            break;
        case 7:
            mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_FR7);
            break;
        default:
            break;
    }
    if (func != 0)
        BITBAND_PORT_SET(mode_base, bit);
    if(dir == PIN_OUTPUT) {
        mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_IE);
        BITBAND_PORT_CLR(mode_base, bit);
        mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_CR);
        BITBAND_PORT_SET(mode_base, bit);
    } else if(dir == PIN_INOUT) {
        mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_IE);
        BITBAND_PORT_SET(mode_base, bit);
        mode_base = BITBAND_PORT_MODE_BASE(port_base, GPIO_Mode_CR);
        BITBAND_PORT_SET(mode_base, bit);
    }
}

void pin_mode(PinName pin, PinMode mode)
{
    int port    = 0;
    uint8_t bit = 0;
    uint8_t val = 0;

    /* Assert that pin is valid*/
    MBED_ASSERT(pin != NC);

    /* Check if function is in range*/
    if (mode > OpenDrain) {
        return;
    }

    /* Calculate port and pin position*/
    port = PIN_PORT(pin);
    bit  = PIN_POS(pin);
    val = (1 << bit);

    switch (port) {
        case PortA:
            if(mode == OpenDrain)  TSB_PA->OD   = val;
            else if(mode == PullUp) TSB_PA->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PA->PDN  = val;
            break;
        case PortB:
            if(mode == OpenDrain)  TSB_PB->OD   = val;
            else if(mode == PullUp) TSB_PB->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PB->PDN  = val;
            break;
        case PortC:
            if(mode == OpenDrain)  TSB_PC->OD   = val;
            else if(mode == PullUp) TSB_PC->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PC->PDN  = val;
            break;
        case PortD:
            if(mode == OpenDrain)  TSB_PD->OD   = val;
            else if(mode == PullUp) TSB_PD->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PD->PDN  = val;
            break;
        case PortE:
            if(mode == OpenDrain)  TSB_PE->OD   = val;
            else if(mode == PullUp) TSB_PE->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PE->PDN  = val;
            break;
        case PortF:
            if(mode == OpenDrain)  TSB_PF->OD   = val;
            else if(mode == PullUp) TSB_PF->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PF->PDN  = val;
            break;
        case PortG:
            if(mode == OpenDrain)  TSB_PG->OD   = val;
            else if(mode == PullUp) TSB_PG->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PG->PDN  = val;
            break;
        case PortH:
            if(mode == PullDown) TSB_PH->PDN  = val;
            break;
        case PortJ:
            if(mode == OpenDrain)  TSB_PJ->OD   = val;
            else if(mode == PullUp) TSB_PJ->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PJ->PDN  = val;
            break;
        case PortK:
            if(mode == OpenDrain)  TSB_PK->OD   = val;
            else if(mode == PullUp) TSB_PK->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PK->PDN  = val;
            break;
        case PortL:
            if(mode == OpenDrain)  TSB_PL->OD   = val;
            else if(mode == PullUp) TSB_PL->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PL->PDN  = val;
            break;
        case PortM:
            if(mode == OpenDrain)  TSB_PM->OD   = val;
            else if(mode == PullUp) TSB_PM->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PM->PDN  = val;
            break;
        case PortN:
            if(mode == OpenDrain)  TSB_PN->OD   = val;
            else if(mode == PullUp) TSB_PN->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PN->PDN  = val;
            break;
        case PortP:
            if(mode == OpenDrain)  TSB_PP->OD   = val;
            else if(mode == PullUp) TSB_PP->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PP->PDN  = val;
            break;
        case PortR:
            if(mode == OpenDrain)  TSB_PR->OD   = val;
            else if(mode == PullUp) TSB_PR->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PR->PDN  = val;
            break;
        case PortT:
            if(mode == OpenDrain)  TSB_PT->OD   = val;
            else if(mode == PullUp) TSB_PT->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PT->PDN  = val;
            break;
        case PortU:
            if(mode == OpenDrain)  TSB_PU->OD   = val;
            else if(mode == PullUp) TSB_PU->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PU->PDN  = val;
            break;
        case PortV:
            if(mode == OpenDrain)  TSB_PV->OD   = val;
            else if(mode == PullUp) TSB_PV->PUP  = val;
            else if(mode == PullDown || mode == PullDefault) TSB_PV->PDN  = val;
            break;
        default:
            break;
    }
}
